package com.syj.qdp.framework.skywalking.core.aop;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.syj.qdp.framework.common.util.sping.SpringExpressionUtils;
import com.syj.qdp.framework.skywalking.core.annotations.BizTrace;
import com.syj.qdp.framework.skywalking.core.util.TracerFrameworkUtils;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.tag.Tags;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.util.Map;

/**
 * @author Lyon
 */
@RequiredArgsConstructor
@Slf4j
@Aspect
public class BizTraceAspect {

    final Tracer tracer;
    private static final String BIZ_OPERATION_NAME_PREFIX = "Biz/";


    @Around("@annotation(trace)")
    @SneakyThrows
    public Object around(ProceedingJoinPoint proceedingJoinPoint, BizTrace trace) {
        /**
         * 创建一个span
         * */
        Span span = buildSpan(proceedingJoinPoint, trace);
        try {
            return proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            TracerFrameworkUtils.error(span, throwable);
            throw throwable;
        } finally {
            try {
                // 设置 span 业务tag
                setSpanTag(proceedingJoinPoint, trace, span);
            } catch (Exception ignore) {}
        }
    }

    private Span buildSpan(ProceedingJoinPoint proceedingJoinPoint, BizTrace bizTrace) {
        try {
            return tracer
                    .buildSpan(buildOperationName(proceedingJoinPoint, bizTrace))
                    .withTag(Tags.COMPONENT.getKey(), BizTrace.SAPN_TYPE)
                    .startManual();
        } catch (Exception ignore) {
        }
        return null;
    }

    private void setSpanTag(ProceedingJoinPoint proceedingJoinPoint, BizTrace trace, Span span) {
        Map<String, Object> expressions = SpringExpressionUtils.parseExpressions(proceedingJoinPoint, ListUtil.of(trace.bizType(), trace.bizId()));
        span.setTag(BizTrace.TYPE_TAG, MapUtil.getStr(expressions, trace.bizType()));
        span.setTag(BizTrace.ID_TAG, MapUtil.getStr(expressions, trace.bizType()));
        span.finish();
    }

    private String buildOperationName(ProceedingJoinPoint proceedingJoinPoint, BizTrace bizTrace) {
        if (StrUtil.isBlank(bizTrace.operationName())) {
            return BIZ_OPERATION_NAME_PREFIX + proceedingJoinPoint.getSignature().toString();
        }
        return BIZ_OPERATION_NAME_PREFIX + bizTrace.operationName();
    }

}
